package model

import (
	"errors"
	"gitee.com/tang_q/gin-vue3-admin-api/global"
	"gitee.com/tang_q/gin-vue3-admin-api/model/dto"
	"gitee.com/tang_q/gin-vue3-admin-api/utils"
	"gorm.io/gorm"
	"strconv"
	"time"
)

type Users struct {
	gorm.Model
	UserName      string     `gorm:"comment:姓名;unique" json:"user_name" validate:"required" form:"user_name"`
	LoginName     string     `gorm:"comment:登录名;unique" json:"login_name" validate:"required" form:"login_name"`
	Password      string     `gorm:"comment:密码" json:"password" validate:"required" form:"password"`
	Roles         []Roles    `gorm:"many2many:users_roles;" json:"roles"`
	Sex           uint8      `gorm:"comment:性别 0:女,1:男" json:"sex" form:"sex"`
	Age           uint8      `gorm:"comment:年龄" json:"age" form:"age"`
	Phone         string     `gorm:"comment:手机号;unique" json:"phone" validate:"required,customValidate" form:"phone"`
	Avatar        string     `gorm:"comment:头像" json:"avatar" form:"avatar"`
	Email         string     `gorm:"comment:邮箱" json:"email" validate:"required,email" form:"email"`
	ClientIp      string     `gorm:"comment:客户端Ip" json:"client_ip" form:"client_ip"`
	Status        int8       `gorm:"comment:状态 0:禁用 1:启用" json:"status" form:"status"`
	CreatedUser   *Users     `gorm:"foreignKey:CreatedUserID" json:"created_user" form:"created_user"`
	CreatedUserID uint       `json:"created_user_id"`
	UpdatedUser   *Users     `gorm:"foreignKey:UpdatedUserID" json:"updated_user" form:"updated_user"`
	UpdatedUserID uint       `json:"updated_user_id"`
	LoginTime     *time.Time `gorm:"comment:登录时间" json:"loginTime" form:"loginTime"`
	LoginOutTime  *time.Time `gorm:"comment:登出时间" json:"loginOutTime" form:"loginOutTime"`
	DeviceInfo    string     `gorm:"comment:设备信息" json:"deviceInfo" form:"deviceInfo"`
}

func init() {
	err := global.DB.AutoMigrate(&Users{})
	if err != nil {
		global.Logger.Error("Users表自动迁移失败!", err)
		return
	}
}
func (u *Users) BeforeDelete(*gorm.DB) (err error) {
	if u.LoginName == "admin" {
		return errors.New("admin用户不允许操作")
	}
	return
}

// GetUsersByLoginName 根据登录用户名获取用户
func (u *Users) GetUsersByLoginName(loginName string) error {
	return global.DB.First(u, "login_name = ?", loginName).Error
}

// GetUserByID 根据用户id获取用户
func (u *Users) GetUserByID(userId uint) error {
	return global.DB.First(u, userId).Error
}

// Create 添加用户
func (u *Users) Create(UserRegisterDTO dto.UserRegisterDTO) error {
	var err error
	u.UserName = UserRegisterDTO.UserName
	u.LoginName = UserRegisterDTO.LoginName
	u.Password = UserRegisterDTO.Password
	u.Sex = UserRegisterDTO.Sex
	u.Age = UserRegisterDTO.Age
	u.Phone = UserRegisterDTO.Phone
	u.Avatar = UserRegisterDTO.Avatar
	u.Email = UserRegisterDTO.Email
	u.Status = UserRegisterDTO.Status
	u.Roles, err = GetRolesByIds(UserRegisterDTO.Roles)
	if err != nil {
		return err
	}

	err = global.DB.Transaction(func(tx *gorm.DB) error {
		// 添加用户
		if err := tx.Create(u).Error; err != nil {
			return err
		}
		// 添加casbin的g权限
		for _, role := range UserRegisterDTO.Roles {
			is, err := utils.AddUserRole(u.LoginName, strconv.Itoa(int(role)))
			if err != nil {
				return err
			}
			if !is {
				return errors.New("添加权限失败")
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}

// Update 更新用户
func (u *Users) Update(data dto.UpdateUserDTO, updateUser *Users) error {
	tx := global.DB.Begin()
	u.ID = data.ID
	// 查找用户
	if err := tx.Find(u).Error; err != nil {
		tx.Rollback()
		return err
	}
	// 清除现有角色
	if err := tx.Model(u).Association("Roles").Clear(); err != nil {
		tx.Rollback()
		return err
	}

	// 更新基本信息
	u.UserName = data.UserName
	u.LoginName = data.LoginName
	u.Password = data.Password
	u.Sex = data.Sex
	u.Age = data.Age
	u.Phone = data.Phone
	u.Email = data.Email
	u.Status = data.Status
	u.UpdatedUser = updateUser
	// 获取新角色
	roles, err := GetRolesByIds(data.Roles)
	if err != nil {
		tx.Rollback()
		return err
	}
	u.Roles = roles

	// 保存用户信息
	if err := tx.Save(u).Error; err != nil {
		tx.Rollback()
		return err
	}
	if utils.GetUserRoleByLoginName(u.LoginName) {
		// 删除casbin的g权限
		role, err := utils.RemoveUserRole(u.LoginName)
		if err != nil {
			tx.Rollback()
			return err
		}
		if !role {
			tx.Rollback()
			return errors.New("删除权限失败")
		}
	}
	for _, role := range roles {
		is, err := utils.AddUserRole(u.LoginName, strconv.Itoa(int(role.ID)))
		if err != nil {
			tx.Rollback()
			return err
		}
		if !is {
			tx.Rollback()
			return errors.New("添加权限失败")
		}
	}
	return tx.Commit().Error
}

// GetMenusRouterThereByLoginName 根据登录用户名获取用户菜单树
func (u *Users) GetMenusRouterThereByLoginName(loginName string) (menusRoutes []*dto.MenuRouteDTO, err error) {
	menus, err := u.GetMenusByLoginName(loginName)
	if err != nil {
		return nil, err
	}
	var menuRoute dto.MenuRouteDTO
	return BuildMenuRouteTree(&menuRoute, menus), nil
}

// GetMenusByLoginName 根据登录用户名获取用户菜单
func (u *Users) GetMenusByLoginName(loginName string) (menus []Menus, err error) {
	// 判断是否有超级管理员角色
	isAdmin, err := u.IsAdminByLoginName(loginName)
	if err != nil {
		return nil, err
	}
	if isAdmin {
		allMenus, err := GetAllMenus()
		if err != nil {
			return nil, err
		}
		return allMenus, nil
	}
	if err := global.DB.Preload("Roles.Menus", "type = ?", 1, func(db *gorm.DB) *gorm.DB {
		return db.Order("sort ASC")
	}).Find(u, "login_name = ?", loginName).Error; err != nil {
		return nil, err
	}
	for _, role := range u.Roles {
		menus = append(menus, role.Menus...)
	}
	return menus, nil
}

// GetButtonsByLoginName 根据用户登录名获取按钮权限
func (u *Users) GetButtonsByLoginName(loginName string) (buttons []string, err error) {
	// 判断是否有超级管理员角色
	isAdmin, err := u.IsAdminByLoginName(loginName)
	if err != nil {
		return nil, err
	}
	if isAdmin {
		getButtons, err := GetButtons()
		if err != nil {
			return nil, err
		}
		return getButtons, nil
	}
	if err := global.DB.Preload("Roles.Menus", "type = ?", 2, func(db *gorm.DB) *gorm.DB {
		return db.Order("sort ASC")
	}).Find(u, "login_name = ?", loginName).Error; err != nil {
		return nil, err
	}
	buttonSet := make(map[string]struct{}) // 使用 map 来避免重复值
	for _, role := range u.Roles {
		for _, menu := range role.Menus {
			if _, exists := buttonSet[menu.Permissions]; !exists {
				buttonSet[menu.Permissions] = struct{}{}
			}
		}
	}

	// 将集合转换为切片
	for button := range buttonSet {
		buttons = append(buttons, button)
	}

	return buttons, nil
}

// GetButtons 获取所有按钮权限
func GetButtons() (buttons []string, err error) {
	var menus []Menus
	err = global.DB.Model(Menus{}).Where("type = ?", 2).Order("sort asc").Find(&menus).Error
	if err != nil {
		return nil, err
	}
	for _, menu := range menus {
		buttons = append(buttons, menu.Permissions)
	}
	return
}

// IsAdminByLoginName 查询是否有管理员角色
func (u *Users) IsAdminByLoginName(loginName string) (bool, error) {
	err := global.DB.Preload("Roles").Find(u, "login_name = ?", loginName).Error
	if err != nil {
		return false, err
	}
	for _, role := range u.Roles {
		if role.Name == "超级管理员" {
			return true, nil
		}
	}
	return false, nil
}

// GetRoleIdsByUserId 根据用户id获取角色ids
func (u *Users) GetRoleIdsByUserId(userId uint) (roleIds []uint, err error) {
	u.ID = userId
	if err = global.DB.Preload("Roles", "is_usable = ?", 1).Find(u).Error; err != nil {
		return nil, err
	}
	for _, role := range u.Roles {
		roleIds = append(roleIds, role.ID)
	}
	return
}

// GetUserList 分页查询用户
func GetUserList(userQueryDTO dto.UserQueryDTO) (userList []Users, total int64, err error) {
	qs := global.DB.Model(&Users{})
	if userQueryDTO.LoginName != "" {
		qs = qs.Where("login_name LIKE ?", "%"+userQueryDTO.LoginName+"%")
	}
	if userQueryDTO.UserName != "" {
		qs = qs.Where("user_name LIKE ?", "%"+userQueryDTO.UserName+"%")
	}
	if userQueryDTO.Email != "" {
		qs = qs.Where("email = ?", userQueryDTO.Email)
	}
	if userQueryDTO.Phone != "" {
		qs = qs.Where("phone = ?", userQueryDTO.Phone)
	}
	if userQueryDTO.RoleName != "" {
		qs = qs.Joins("JOIN users_roles ON users_roles.users_id = users.id").
			Joins("JOIN roles ON users_roles.roles_id = roles.id").
			Where("roles.name = ?", userQueryDTO.RoleName)
	}
	if userQueryDTO.Status == 0 || userQueryDTO.Status == 1 {
		qs = qs.Where("status = ?", userQueryDTO.Status)
	}
	qs.Count(&total)
	err = qs.Preload("Roles").Preload("CreatedUser").Preload("UpdatedUser").Offset((userQueryDTO.Page - 1) * userQueryDTO.PageSize).Limit(userQueryDTO.PageSize).Order("id asc").Find(&userList).Error
	return
}

// DeleteUser 删除用户
func DeleteUser(id string) error {
	var user Users
	if err := global.DB.Find(&user, id).Error; err != nil {
		return err
	}
	// 开启自动事务
	if err := global.DB.Transaction(func(tx *gorm.DB) error {
		// 清空用户的casbin权限
		if utils.GetUserRoleByLoginName(user.LoginName) {
			role, err := utils.RemoveUserRole(user.LoginName)
			if err != nil {
				return err
			}
			if !role {
				return errors.New("删除权限失败")
			}
		}
		// 清空用户角色关联
		if err := tx.Model(&user).Association("Roles").Clear(); err != nil {
			return err
		}
		// 删除用户
		if err := tx.Delete(&user).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// DeleteUsers 批量删除用户
func DeleteUsers(data dto.DelUserByIDsReq) error {
	var userList []Users
	global.DB.Where("id IN ?", data.Ids).Find(&userList)
	// 开启自动事务
	if err := global.DB.Transaction(func(tx *gorm.DB) error {
		// 清空用户角色关联
		if err := tx.Model(&userList).Association("Roles").Clear(); err != nil {
			return err
		}
		// 删除用户
		if err := tx.Unscoped().Delete(&userList).Error; err != nil {
			return err
		}
		// 删除用户的casbin权限
		for _, user := range userList {
			if utils.GetUserRoleByLoginName(user.LoginName) {
				role, err := utils.RemoveUserRole(user.LoginName)
				if err != nil {
					return err
				}
				if !role {
					return errors.New("删除权限失败")
				}
			}
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// UpdateLoginTime 更新登录时间
func UpdateLoginTime(id uint) error {
	var user Users
	if err := global.DB.Find(&user, id).Error; err != nil {
		return err
	}
	// 更新登录时间
	global.DB.Model(&user).Update("login_time", time.Now())
	return nil
}

// UpdateUserInfo 个人中心更改信息
func (user *Users) UpdateUserInfo(data dto.UpdateUserInfoDTO) error {
	if err := global.DB.Find(user, data.ID).Error; err != nil {
		return err
	}
	// 更新用户信息
	user.UserName = data.UserName
	user.LoginName = data.LoginName
	user.Phone = data.Phone
	user.Email = data.Email
	user.Sex = data.Sex
	user.Age = data.Age
	user.Password = data.Password
	if err := global.DB.Save(user).Error; err != nil {
		return err
	}
	return nil
}

// UpdateAvatar 更新头像
func (user *Users) UpdateAvatar(avatar string) error {
	// 更新用户之前删除上传的图片
	if user.Avatar != "" {
		if err := utils.DeleteAvatar(user.Avatar); err != nil {
			return err
		}
	}
	// 更新头像
	if err := global.DB.Model(user).Update("avatar", avatar).Error; err != nil {
		return err
	}
	return nil
}
